Title with entity tile
canonIdentity of the Section top bar: exactly one of icon, colour tile, avatar, heading dropdown or inline rename.
Rule confirmed in code on meeting detail (acrm !4014, 27 Sep 2026): a record that IS a thing, not an identity, gets the flat `icon` prop (20px, `--fg-secondary`) inherited from its section's menu mark — `MeetingDetailPage.tsx` passes `entityMark(...).icon` from the Kalendář mark, same as Deals/Tasks; no 32px `kind` tile, since a meeting is not a person or a company.
Used in 55 files · 49 areas · 70× — components/PageHeader, components/agent-desk, components/datamart, components/segment, pages/AccountingInvoiceDetailPage, pages/AccountingInvoiceEditPage …
Default
export const Default = () => (
<div
style={{
border: '1px solid var(--border)',
borderRadius: 'var(--radius-lg)',
overflow: 'hidden',
background: 'var(--bg-canvas)',
}}
>
<SectionTopBar title={<SectionTopBarTitle name="Firmy" tileIcon="building" tone="blue" />}>
<SectionTopBarSpacer />
</SectionTopBar>
<div style={{ height: 'var(--sp-6)' }} />
</div>
);Variants
flat icon — the section is an icon row in the menu (Úkoly, Email, Hovory)
colour tile — the section is a coloured sub-item in the menu; same glyph and tone as there, not a status
avatar — a person's record; the initials and hue come from the name
heading dropdown — the title itself opens a menu (switching pipelines); it gets a chevron and a hover surface
inline rename — click the name, type, Enter saves and Escape cancels; nothing is saved when the value did not change
export const Variants = () => {
const [name, setName] = useState('Bonitní Pražané');
return (
<div style={{ display: 'grid', gap: 'var(--sp-5)' }}>
<Frame text="flat icon — the section is an icon row in the menu (Úkoly, Email, Hovory)">
<SectionTopBar title={<SectionTopBarTitle name="Úkoly" icon="checkbox" />} />
</Frame>
<Frame text="colour tile — the section is a coloured sub-item in the menu; same glyph and tone as there, not a status">
<SectionTopBar
title={<SectionTopBarTitle name="Projekty" tileIcon="category" tone="lime" />}
/>
</Frame>
<Frame text="avatar — a person's record; the initials and hue come from the name">
<SectionTopBar title={<SectionTopBarTitle name="Josef Novák" avatar />} />
</Frame>
<Frame text="heading dropdown — the title itself opens a menu (switching pipelines); it gets a chevron and a hover surface">
<SectionTopBar
title={
<PickerMenu
trigger={(o) => (
<SectionTopBarTitle
name="Obecná pipeline"
tileIcon="layout-columns"
tone="blue"
open={o}
onClick={() => {}}
/>
)}
items={[
{ key: 'obecna', name: 'Obecná pipeline', icon: 'layout-columns' },
{ key: 'tym', name: 'Obchodní tým', icon: 'briefcase' },
]}
value="obecna"
onPick={() => {}}
/>
}
/>
</Frame>
<Frame text="inline rename — click the name, type, Enter saves and Escape cancels; nothing is saved when the value did not change">
<SectionTopBar
title={
<SectionTopBarTitle
name={name}
tileIcon="filter"
tone="green"
onRename={setName}
renameHint="Přejmenovat segment"
/>
}
/>
</Frame>
</div>
);
};States
all seven tones — the tile carries the section's colour; nothing else in the bar is coloured
menu open — the heading keeps the open state so the reader sees where the menu belongs
saving a rename — the field cannot be reopened until the save comes back (renaming)
long name — the title takes the room it needs; the controls after it keep their place because the bar scrolls rather than squeezes
export const States = () => (
<div style={{ display: 'grid', gap: 'var(--sp-5)' }}>
<Frame text="all seven tones — the tile carries the section's colour; nothing else in the bar is coloured">
<div
style={{
display: 'flex',
flexWrap: 'wrap',
gap: 'var(--sp-3)',
padding: 'var(--sp-3) var(--sp-5)',
}}
>
{TONES.map((tone) => (
<SectionTopBarTitle key={tone} name={tone} tileIcon="target" tone={tone} />
))}
</div>
</Frame>
<Frame text="menu open — the heading keeps the open state so the reader sees where the menu belongs">
<SectionTopBar
title={
<SectionTopBarTitle
name="Obecná pipeline"
tileIcon="layout-columns"
tone="blue"
open
onClick={() => {}}
/>
}
/>
</Frame>
<Frame text="saving a rename — the field cannot be reopened until the save comes back (renaming)">
<SectionTopBar
title={
<SectionTopBarTitle
name="Bonitní Pražané"
tileIcon="filter"
tone="green"
onRename={() => {}}
renaming
/>
}
/>
</Frame>
<Frame text="long name — the title takes the room it needs; the controls after it keep their place because the bar scrolls rather than squeezes">
<SectionTopBar
title={
<SectionTopBarTitle
name="Retenční kampaň pro bonitní klienty Praha a Střední Čechy 2026"
tileIcon="filter"
tone="amber"
/>
}
/>
</Frame>
</div>
);Composition
export const Composition = () => {
const [name, setName] = useState('Josef Novák');
return (
<div
style={{
border: '1px solid var(--border)',
borderRadius: 'var(--radius-lg)',
overflow: 'hidden',
background: 'var(--bg-canvas)',
}}
>
<SectionTopBar
title={
<SectionTopBarTitle name={name} avatar onRename={setName} renameHint="Přejmenovat" />
}
>
<SectionTopBarSpacer />
</SectionTopBar>
<div style={{ padding: 'var(--sp-5)', color: 'var(--fg-muted)', font: 'var(--small)' }}>
Detail osoby — the identity is the avatar plus the name, and the name is editable in place;
the record type is never spelled out in the title.
</div>
</div>
);
};